import * as async from 'async';
import * as fse from 'fs-extra';
// @ts-ignore
import * as logger from 'haiku-serialization/src/utils/LoggerInstance';
import * as path from 'path';
// @ts-ignore
import * as rollup from 'rollup';
// @ts-ignore
import * as commonjs from 'rollup-plugin-commonjs';
// @ts-ignore
import * as includePaths from 'rollup-plugin-includepaths';
// @ts-ignore
import * as json from 'rollup-plugin-json';
// @ts-ignore
import * as nodeResolve from 'rollup-plugin-node-resolve';
// @ts-ignore
import * as uglify from 'rollup-plugin-uglify-es';

import {HaikuProject} from 'haiku-sdk-creator/lib/bll/Project';
import {
  getCopyrightNotice,
  getCurrentHumanTimestamp,
  getEmbedName,
  getOrganizationNameOrFallback,
  getStandaloneName,
} from './ProjectDefinitions';

const createBundle = (moduleDirectory: string, input: string, name: string, cb: any) => {
  logger.info('[bundler] beginning in basedir', moduleDirectory);

  rollup.rollup({
    input,
    plugins: [
      includePaths({
        include: {
          '@haiku/core': require.resolve('@haiku/core'),
          '@haiku/core/dom': require.resolve('@haiku/core/dom'),
          '@haiku/core/components/controls/Image/code/main/code':
            require.resolve('@haiku/core/components/controls/Image/code/main/code'),
          '@haiku/core/components/controls/Font/code/main/code':
            require.resolve('@haiku/core/components/controls/Font/code/main/code'),
          '@haiku/core/components/controls/Text/code/main/code':
            require.resolve('@haiku/core/components/controls/Text/code/main/code'),
          // Note how we're pointing legacy player to core here
          '@haiku/player': require.resolve('@haiku/core'),
          '@haiku/player/dom': require.resolve('@haiku/core/dom'),
        },
      }),
      nodeResolve({
        jsnext: true,
        main: true,
      }),
      commonjs({
        sourceMap: false,
        extensions: ['.js'],
      }),
      json(),
      uglify(),
    ],
  }).then((bundle: any) => {
    bundle.generate({
      name,
      // Although this is not ideal, we can't force our users to write strict code.
      strict: false,
      format: 'iife',
    }).then(({code}: any) => {
      cb(null, code);
    }).catch((err: any) => {
      cb(err);
    });
  }).catch((err: any) => {
    cb(err);
  });
};

export const createCDNBundles = (
  project: HaikuProject,
  finish: (err: any) => void,
) => {

  const organizationName = getOrganizationNameOrFallback(project.organizationName);
  const embedName = getEmbedName(organizationName, project.projectName);
  const standaloneName = getStandaloneName(organizationName, project.projectName);

  const autoGeneratedNotice = `This file was autogenerated by Haiku at ${getCurrentHumanTimestamp()}.`;
  const copyrightNotice = getCopyrightNotice(organizationName);

  logger.info('[project folder] creating cdn bundles');
  return async.parallel([
    (cb) => {
      logger.info('[project folder] bundling code/main/dom-embed.js');
      return createBundle(
        path.join(project.projectPath, 'code/main'),
        path.join(project.projectPath, 'code/main/dom-embed.js'),
        embedName,
        (bundleErr: any, bundledContents: any) => {
          if (bundleErr) {
            return cb(bundleErr);
          }
          logger.info('[project folder] bundling succeeded for', embedName);
          const finalContent = `/** ${autoGeneratedNotice}\n${copyrightNotice}\n*/\n${bundledContents}`;
          fse.outputFileSync(path.join(project.projectPath, 'index.embed.js'), finalContent);
          return cb();
        },
          );
    },
    (cb) => {
      logger.info('[project folder] bundling code/main/dom-standalone.js');
      return createBundle(
        path.join(project.projectPath, 'code/main'),
        path.join(project.projectPath, 'code/main/dom-standalone.js'),
        standaloneName,
        (bundleErr: any, bundledContents: any) => {
          if (bundleErr) {
            return cb(bundleErr);
          }
          logger.info('[project folder] bundling succeeded for', standaloneName);
          const finalContent = `/** ${autoGeneratedNotice}\n${copyrightNotice}\n*/\n${bundledContents}`;
          fse.outputFileSync(path.join(project.projectPath, 'index.standalone.js'), finalContent);
          return cb();
        },
      );
    },
  ], (asyncErr) => {
    if (asyncErr) {
      return finish(asyncErr);
    }
    return finish(null);
  });
};
